#!/bin/bash
if [[ $(whoami) != "root" ]]; then
	echo "Please log in as user root...";
	exit 1;
fi
source /sources/pkg/pkglib.sh || exit 1
cd /usr/pkg || exit 1

USAGE="$0 COMMAND [PACKAGE [VERSION]]

	COMMAND - package commands
		install		install package PACKAGE with VERSION
		search		list all packages starting with PACKAGE or when PACKAGE is empty, list all
		remove		remove package PACKAGE (all versions installed)
		clean		remove unzipped package data and log files of PACKAGE under /usr/pkg/
		update		update package sources and archive folder
        upgrade     upgrade package PACKAGE to version VERSION
        deps        show all dependencies of package PACKAGE with VERSION (recursively)
        locked      show all packages that are depending on package PACKAGE with VERSION
        autoremove  remove all unneeded packages (but only packages with *_pkg.lock file)
		
	e.g.	$0 install glibc
				--> install package glibc
			$0 search glibc
				--> list all packages starting with glibc
";

COMMAND=$1;
PACKAGE=$2;
VERSION=$([ ! -z $3 ] && echo $3 || echo '.*');
if [ -z $COMMAND ]; then
	errcho "Argument COMMAND missing... ";
	errcho "";
	errcho "$USAGE";
	exit 1;
fi

[ -d /usr/pkg/installed.db ] || { mkdir -p /usr/pkg/installed.db && chown lfs:lfs /usr/pkg/installed.db; } || exit 48;

if [[ $COMMAND == "install" || $COMMAND == "remove" || $COMMAND == "upgrade" || $COMMAND == "clean" || $COMMAND == "deps" || $COMMAND == "locked" ]]; then
    if [ -z $PACKAGE ]; then
		errcho "Argument PACKAGE missing...";
		errcho "";
		errcho "$USAGE";
		exit 2;
	fi
    # match exactly
    PKGS="$(pkgsearch $PACKAGE)"; if (($? != 0)); then exit 25; fi
elif [[ $COMMAND == "update" ]]; then
	if [[ $(whereis wget | sed -e 's|^wget:||') != "" ]]; then
		su -p -c "PATH=$PATH; wget -nc -i /sources/prepare/wget-list -P /sources > /dev/null" lfs || 
			errcho "Failed to download source packages of group basic";
		su -p -c "PATH=$PATH; wget -nc -i /sources/pkg/extra/wget-list -P /sources > /dev/null" lfs || 
			errcho "Failed to download source packages of group extra";
		chown -R lfs:lfs /sources || exit 33;
	else
		errcho "Tool wget missing... please install package extra/wget-notls or extra/wget first (/source/pkg/basic/make_wget.sh && $0 install wget)";
		exit 34;
	fi
	exit;
elif [[ $COMMAND == "autoremove" ]]; then
    # collect all packages, that have an lock-file but are not locked anymore
    PKGS="$(pkgunlocked '*')"; if (($? != 0)); then exit 56; fi
elif [[ $COMMAND == "search" ]]; then
    # search by pattern
    PKGS="$(pkgsearch -p $PACKAGE)"; if (($? != 0)); then exit 25; fi
else
    # command unknown
    errcho "COMMAND $COMMAND unknown...";
	errcho "";
	errcho "$USAGE";
	exit 46;
fi

# collect all available packages
if [[ $PKGS == "" ]]; then
	errcho "No matching package(s) found...";
	exit 28;
fi
PKGMATCHES=0;
PKG_BATCH="";
for pkg in $PKGS; do
	PKG_INFO="$(pkginfo $pkg)";
	if (($? == 0)); then
		PKG_NAME=$pkg;
		PKG_VERSION=$(pkgversions $PKG_NAME | grep "^${VERSION}$" | head -1) && \
		[ ! -z "$PKG_VERSION" ] && [ ! -z "$PKG_NAME" ] && \
		PKG_ARCHIVE=${PKG_NAME}_${PKG_VERSION}_pkg.tar.gz || \
			{ errcho "Unknown package version"; exit 30; }
        if [[ $COMMAND == "autoremove" ]]; then
            PKG_BATCH=$(echo "$PKG_BATCH" | grep -v '^$'; echo "$PKG_NAME $PKG_ARCHIVE $PKG_VERSION");
        elif [[ $COMMAND == "deps" ]]; then
            PKG_DEPS="$(pkgdepstree $PKG_NAME $PKG_VERSION)" || exit 49;
            if [[ $PKG_DEPS != "" ]]; then
                errcho "$PKG_NAME $PKG_VERSION has following dependencies (recursively):";
                echo "$PKG_DEPS";
            else
                errcho "$PKG_NAME $PKG_VERSION has no dependencies";
            fi
        elif [[ $COMMAND == "locked" ]]; then
            PKG_LOCKS="$(pkglockedby $PKG_NAME $PKG_VERSION)" || exit 50;
            if [[ $PKG_LOCKS != "" ]]; then
                errcho "$PKG_NAME $PKG_VERSION is a dependency of installed package(s):";
                echo "$PKG_LOCKS";
            else
                errcho "$PKG_NAME $PKG_VERSION is no dependency of other installed packages";
            fi
        else
            echo "$PKG_INFO";
        fi
		PKGMATCHES=$(($PKGMATCHES+1));
	else
		exit 29;
	fi
done

# check package name match
if [[ $COMMAND == "install" || $COMMAND == "remove" || $COMMAND == "upgrade" || $COMMAND == "clean" ]]; then
	if (($PKGMATCHES == 0)); then
		errcho "Package $PACKAGE not found";
		exit 3;
	elif (($PKGMATCHES != 1)); then
		errcho "More than one package match the PACKAGE argument ($PACKAGE)... please specify a clearly unique package name";
		exit 4;
	elif [ -z $PKG_NAME ]; then
		errcho "Package name missing... $PKG_NAME";
		exit 5;
	elif [ -z $PKG_VERSION ]; then
		errcho "Package version missing... $PKG_VERSION";
		exit 6;
	elif [[ $PACKAGE != $PKG_NAME ]]; then
		errcho "Given package name ($PACKAGE) and package found ($PKG_NAME) dosn't match.";
		exit 26;
	fi
elif [[ $COMMAND == "autoremove" ]]; then
    if (($PKGMATCHES == 0)) || [[ $PKG_BATCH == "" ]]; then
		errcho "Nothing to remove...";
		exit 57;
    else
        errcho "--> $PKGMATCHES unneeded package$([[ $PKGMATCHES != "1" ]] && echo s;) found:"
        errcho "$(echo "$PKG_BATCH" | cut -d' ' -f1,3 | tr -s [:blank:] '-' | tr -s [:space:] ' ')";
        read -p "Remove this packages [y/n]? " ANSWER || exit 58;
        if [[ $ANSWER != "y"* ]]; then
            exit 59;
        fi
    fi
fi

if [[ $COMMAND == "clean" ]]; then
	# remove unzipped package data
	rm -Rf "${PKG_NAME}" > /dev/null && \
	rm -f installed.db/${PKG_NAME}_*_pkg.log > /dev/null && \
	rm -f installed.db/${PKG_NAME}_*_pkg.err > /dev/null;
	if (($? != 0)); then
		exit 27;
	fi
	
elif [[ $COMMAND == "install" || $COMMAND == "upgrade" ]]; then
	# check, if package already installed
    INSTVERS=$(pkginstver $PKG_NAME) || exit 52;
    if [[ $COMMAND == "install" && $INSTVERS != "" ]]; then
		errcho "Package already installed (see /usr/pkg/installed.db)";
		errcho "Installed: $PKG_NAME $(echo "$INSTVERS" | tr -s '[:space:]' ',' | sed -e 's|,$||')";
		exit 14;
	elif [[ $COMMAND == "upgrade" ]]; then
        PKG_OLD=$(echo "$INSTVERS" | grep -v '^$' | head -1);
        if [[ $PKG_OLD == "" ]]; then
            errcho "Package $PKG_NAME not installed, upgrade not possible";
            exit 53;
        elif [[ $(versionmatch $PKG_VERSION $INSTVERS 2> /dev/null) != "" ]]; then
            errcho "Package version installed is up to date (see /usr/pkg/installed.db)";
            errcho "Installed: $PKG_NAME $(echo "$INSTVERS" | tr -s '[:space:]' ',' | sed -e 's|,$||')";
            exit 54;
        fi
        # keep old log file
        mv -f /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.log /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
        mv -f /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.err /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.err;
    else
        # clean log file from broken installation
        rm -f /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
        rm -f /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.err;
    fi
	# check dependencies
	DEPSTREE="$(pkgmakechain "$PKG_NAME" "$PKG_VERSION")" || { errcho "Abort install..."; exit 31; }
	DEPSTREE="$(echo "$DEPSTREE" | tr -s [:blank:] '-' | tr -s [:space:] ' ' | sed -e 's| $||' | sed -e 's|^ ||')";
	if [[ $DEPSTREE != "" ]]; then
		errcho "Package dependencies not satisfied; missing:";
		errcho $DEPSTREE;
		exit 32;
	fi
	# check conflicts
	PKG_CONFL="";
    CONFL_CACHE=$(pkggetconflicts);
	IFS=$'\n';
	for c in $CONFL_CACHE; do
		if [[ $(pkginstver $c) != "" ]]; then
			PKG_CONFL="${PKG_CONFL}$(echo $c)";
		fi
	done
	if [[ $PKG_CONFL != "" ]]; then
		errcho "Package and/or its dependencies are in conflict with installed packages:";
		errcho $(echo "$PKG_CONFL" | tr -s '[:space:]' ' ');
		exit 35;
	fi
	# collect direct dependencies
	PKG_DEPS=$(pkgdeps $PKG_NAME $PKG_VERSION) || exit 36;
	# start installation
	errcho $(echo "-- Install $PKG_NAME $PKG_VERSION $PKG_ARCHIVE --" | \
		tee -a /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log | tee -a /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.err);

    # clean old package folder
    rm -Rf "${PKG_NAME}" > /dev/null || exit 39;

	# install package
	if [ -d /usr/pkg/$PKG_NAME ]; then
		rm -Rfv /usr/pkg/$PKG_NAME >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 18;
	fi
	mkdir -pv /usr/pkg/$PKG_NAME >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log && \
	cd /usr/pkg/$PKG_NAME && \
	tar -xvvzf ../$PKG_ARCHIVE >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log && \
	cd $PKG_VERSION || exit 7;
	# copy into root
	# update owner and group on package directory
	for f in $(find ./inst/ -user lfs -o -group lfs); do		
		PERM=$(stat -c '%U:%G' $f) || exit 8;
		NEWPERM=$(echo $PERM | sed -e 's|lfs:|root:|' | sed -e 's|:lfs|:root|');
		if (($? != 0)); then exit 9; fi;
		if [[ $PERM != $NEWPERM ]]; then
			echo "found permission $PERM of file $f --> $NEWPERM" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
			chown -hv $(echo $NEWPERM) $f >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 10;
		fi
	done
	# copy files and make destination directories
	BASEDIR="./inst";
	for f in $(find ./inst/ -type l -o -type f -o -type d -empty); do
		FNAME=$(echo $f | grep '^./inst/.*' | sed -e 's|^./inst/|/|');
		if [[ $FNAME != "/" && $(echo $FNAME | grep '^./inst') == "" ]]; then
			# prepare destination directory
			DESTDIR=$(dirname $FNAME) || exit 20;
			BD=$(dirname $f);
			if [[ $BD != $BASEDIR ]]; then
				BASEDIR=$BD;
				echo "new destination sub-directory: $DESTDIR" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
				if [ -h $DESTDIR ]; then
					echo "destination directory $DESTDIR is an symbolic link, keep it" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
				elif [ -e $DESTDIR ]; then
					if [ -d $DESTDIR ]; then
						echo "destination directory $DESTDIR exists, keep it" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
					else
						echo "destination directory $DESTDIR exists, but is not a directory!" | \
							tee -a /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.err >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
						errcho "destination directory $DESTDIR exists, but is not a directory!";
						exit 21;
					fi
				else
					# check if special owner settings must be apply
					if [[ $DESTDIR != "/" ]]; then
						mkdir -pv $DESTDIR >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 19;
						echo "update ownership and permissions of $DESTDIR" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
						PERM=$(stat -c '%U:%G:%a' $BASEDIR);
						if (($? != 0)); then exit 22; fi;
						NEWPERM=$(echo $PERM | cut -d: -f1,2 | sed -e 's|lfs:|root:|' | sed -e 's|:lfs|:root|');
						ACCESS=$(echo $PERM | cut -d: -f3);
						if (($? != 0)); then exit 23; fi;
						if [[ $NEWPERM != "root:root" ]]; then
							echo "found permission $PERM of directory $DESTDIR --> $NEWPERM" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
							chown -hv $(echo $NEWPERM) $DESTDIR >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 24;
						fi
						echo "set access rights of directory $DESTDIR --> $ACCESS" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
						chmod -v $(echo $ACCESS) $DESTDIR >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 24;
					fi
				fi
			fi
			
			if [ -h $FNAME ]; then
				# destination is an symbolic link
				RL=$(readlink $FNAME) && \
				echo "rm symlink: '"$FNAME"' --> '"$RL"'" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.files || exit 11;
				# remove symbolic link
				echo "rm: $FNAME (symbolic link)" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
				rm -vf $FNAME >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 11;
			fi
			# check slash ending...
			if [[ $(echo $DESTDIR | grep '/$') == "" ]]; then
				DESTDIR=$DESTDIR"/";
			fi
			# copy
			cp -afv --remove-destination $f $DESTDIR >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 11;
		fi
	done;
	
	# execute setup script
	if [[ -x ./setup.sh ]]; then
		./setup.sh;
		ERR=$?;
		if (($ERR != 0)); then
			errcho "$0: setup script aborted with error id $ERR";
			exit 12;
		fi
	else
		echo "-- info: no setup.sh script found... --" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
	fi
	
	# append archive file information
	tar -ztf /usr/pkg/$PKG_ARCHIVE | grep "^${PKG_VERSION}/inst/.*" | sed -e "s|^${PKG_VERSION}/inst/|/|" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.files || exit 13;

	# append to database
	cp -vf ./pkg.info /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.info >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 13;

    # take locks of previous version of the package
    if [[ $COMMAND == "upgrade" ]]; then
        [ ! -e /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.lock ] || \
            cp -vf /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.lock /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.lock  >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || \
            exit 55;
    fi

	# lock dependent packages
	IFS=$'\n';
	for d in $PKG_DEPS; do
		if [[ $d != "" && $d != "!"* ]]; then
            #errcho "$0: register $PKG_NAME in its depending package $d";
			DEP_NAME=$(echo $d | cut -d' ' -f1);
            INSTVERS=$(pkginstver $DEP_NAME) || exit 43;
            if (($(echo $d | wc -w) >= 2)); then
                DEP_MINVERSION=$(echo $d | cut -d' ' -f2);
                DEP_VERSION=$(versionmatch $DEP_MINVERSION $INSTVERS 2> /dev/null);
            else
                DEP_VERSION=$(echo "$INSTVERS" | grep -v '^$' | head -1) || { errcho "$0: Failed to determine installed package version of $DEP_NAME"; exit 44; };
            fi
            # check version number
            if [[ $DEP_VERSION == "" ]]; then
                errcho "$0: Failed to determine installed package version of $DEP_NAME";
                exit 51;
            fi
            # register lock
			if [ ! -e /usr/pkg/installed.db/${DEP_NAME}_${DEP_VERSION}_pkg.lock ] || \
				[[ $(cat /usr/pkg/installed.db/${DEP_NAME}_${DEP_VERSION}_pkg.lock | grep "^${PKG_NAME} ${PKG_VERSION}$") == "" ]]
			then
				echo "${PKG_NAME} ${PKG_VERSION}" >> /usr/pkg/installed.db/${DEP_NAME}_${DEP_VERSION}_pkg.lock;
				echo "append dependency lock into: /usr/pkg/installed.db/${DEP_NAME}_${DEP_VERSION}_pkg.lock" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
			else
				echo "dependency lock already made in: /usr/pkg/installed.db/${DEP_NAME}_${DEP_VERSION}_pkg.lock" >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
			fi
		fi
	done

	# remove folder
	if [[ $PKG_NAME != "" ]]; then
		cd /usr/pkg && rm -Rfv /usr/pkg/$PKG_NAME >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 16;
	else
		errcho "PKG_NAME is empty... abort";
		exit 17;
	fi

    # remove old package
    if [[ $COMMAND == "upgrade" ]]; then
        _pkgremove $PKG_NAME $PKG_OLD $PKG_VERSION || exit 42;
        # append old log file to new package log
        cat /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.log >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log;
        rm -Rvf /usr/pkg/installed.db/${PKG_NAME}_${PKG_OLD}_pkg.* >> /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log || exit 45;
    fi

	# INSTALL OK
	errcho $(echo "$0: package $PKG_NAME ($PKG_VERSION) installed" | tee -a /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log);
	errcho " --OK --";

elif [[ $COMMAND == "remove" || $COMMAND == "autoremove" ]]; then
    
    if [[ $PKG_BATCH == "" ]]; then
        PKG_BATCH="$PKG_NAME $PKG_ARCHIVE $PKG_VERSION";
    fi
    
	IFS=$'\n';
    for pkg in $PKG_BATCH; do
        PKG_NAME=$(echo $pkg | cut -d' ' -f1);
        PKG_VERSION=$(echo $pkg | cut -d' ' -f3);
        if [ ! -r /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.files ]; then
            errcho "Can not find ${PKG_NAME}_${PKG_VERSION}_pkg.files info";
            exit 40;
        fi

        # check dependency lock
        PKG_LOCKED_BY=$(pkglockedby $PKG_NAME $PKG_VERSION) || exit 37;
        if [[ $PKG_LOCKED_BY != "" ]]; then
            errcho "Package $PKG_NAME $PKG_VERSION is a dependency of package(s):";
            errcho "$PKG_LOCKED_BY";
            exit 38;
        else
            echo "No depending package installed";
        fi

        errcho $(echo "-- Remove $PKG_NAME $PKG_VERSION --" | \
            tee /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.log | tee /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.err);

        # remove files and directories
        _pkgremove $PKG_NAME $PKG_VERSION || exit 41;

        # remove installed.db info
        rm -f /usr/pkg/installed.db/${PKG_NAME}_${PKG_VERSION}_pkg.* || exit 47;
        errcho "$0: package $PKG_NAME ($PKG_VERSION) removed";
        errcho " --OK --";
    done
fi

exit $?
